﻿namespace XDesignerCommon
{
    using System;
    using System.Drawing;
    using XDesignerDrawer;

    public sealed class MathCommon
    {
        private MathCommon()
        {
        }

        public static double Angle(double x1, double y1, double x2, double y2)
        {
            if (x1 == x2)
            {
                if (y2 >= y1)
                {
                    return 90.0;
                }
                return 270.0;
            }
            double dblAngle = Math.Atan((y2 - y1) / (x2 - x1));
            dblAngle = (180.0 * dblAngle) / 3.1415926535897931;
            if (x2 >= x1)
            {
                if (y2 >= y1)
                {
                    return dblAngle;
                }
                return (dblAngle + 360.0);
            }
            return (dblAngle + 180.0);
        }

        public static int[] BubbleSort(int[] Values)
        {
            int length = Values.Length;
            int[] indexs = new int[length];
            for (int iCount = 0; iCount < length; iCount++)
            {
                indexs[iCount] = iCount;
            }
            int temp = 0;
            int f = length;
            while (f > 0)
            {
                int k = f - 1;
                f = 0;
                for (int j = 0; j < k; j++)
                {
                    if (Values[indexs[j]] > Values[indexs[j + 1]])
                    {
                        temp = indexs[j];
                        indexs[j] = indexs[j + 1];
                        indexs[j + 1] = temp;
                        f = j;
                    }
                }
            }
            return indexs;
        }

        public static int[] CalcuteAlignPosition(int[] Widths, int Spacing, int ContentWidth, StringAlignment Align, bool SplitBlank)
        {
            if (Align == StringAlignment.Near)
            {
                return CalcuteAlignPosition(Widths, Spacing, ContentWidth, 0, SplitBlank);
            }
            if (Align == StringAlignment.Center)
            {
                return CalcuteAlignPosition(Widths, Spacing, ContentWidth, 1, SplitBlank);
            }
            if (Align == StringAlignment.Far)
            {
                return CalcuteAlignPosition(Widths, Spacing, ContentWidth, 2, SplitBlank);
            }
            return null;
        }

        public static int[] CalcuteAlignPosition(int[] Widths, int Spacing, int ContentWidth, int Align, bool SplitBlank)
        {
            if (Widths.Length == 0)
            {
                return null;
            }
            int[] Result = new int[Widths.Length];
            if (Widths.Length == 1)
            {
                if (Align == 0)
                {
                    Result[0] = 0;
                    return Result;
                }
                if (Align == 1)
                {
                    Result[0] = (ContentWidth - Widths[0]) / 2;
                    return Result;
                }
                if (Align == 2)
                {
                    Result[0] = ContentWidth - Widths[0];
                    return Result;
                }
                if (Align == 3)
                {
                    Result[0] = (ContentWidth - Widths[0]) / 2;
                }
                return Result;
            }
            int TotalWidth = 0;
            for (int iCount = 0; iCount < Widths.Length; iCount++)
            {
                TotalWidth = (TotalWidth + Widths[iCount]) + Spacing;
            }
            TotalWidth -= Spacing;
            int PosCount = 0;
            if (Align == 0)
            {
                PosCount = 0;
            }
            else if (Align == 1)
            {
                if (SplitBlank)
                {
                    PosCount = 0;
                }
                else
                {
                    PosCount = (ContentWidth - TotalWidth) / 2;
                }
            }
            else if (Align == 2)
            {
                if (SplitBlank)
                {
                    PosCount = 0;
                }
                else
                {
                    PosCount = ContentWidth - TotalWidth;
                }
            }
            else if (Align == 3)
            {
                PosCount = 0;
                SplitBlank = true;
            }
            for (int iCount = 0; iCount < Widths.Length; iCount++)
            {
                Result[iCount] = PosCount;
                PosCount = (PosCount + Widths[iCount]) + Spacing;
            }
            if (SplitBlank)
            {
                int TotalDis = ContentWidth - TotalWidth;
                if (TotalDis > 0)
                {
                    int iStep = (int) Math.Ceiling((double) (((double) TotalDis) / ((double) (Widths.Length - 1))));
                    int StepCount = 0;
                    for (int iCount = 0; iCount < Result.Length; iCount++)
                    {
                        Result[iCount] += StepCount;
                        StepCount += iStep;
                        if (StepCount > TotalDis)
                        {
                            StepCount = TotalDis;
                        }
                    }
                }
            }
            return Result;
        }

        public static int CloseWithBorder(double vLeft, double vTop, double vWidth, double vHeight, double x, double y, double MaxDistance)
        {
            double vRight = vLeft + vWidth;
            double vBottom = vTop + vHeight;
            if ((x >= vLeft) && (x <= vRight))
            {
                if (Math.Abs((double) (x - vLeft)) <= MaxDistance)
                {
                    return 3;
                }
                if (Math.Abs((double) (x - vRight)) <= MaxDistance)
                {
                    return 1;
                }
            }
            if ((y >= vTop) && (y <= vBottom))
            {
                if (Math.Abs((double) (y - vTop)) <= MaxDistance)
                {
                    return 0;
                }
                if (Math.Abs((double) (y - vBottom)) <= MaxDistance)
                {
                    return 2;
                }
            }
            return -1;
        }

        public static int ColorToInt32(Color Color)
        {
            return (Color.ToArgb() & 0xffffff);
        }

        public static int Distance(int x1, int y1, int x2, int y2)
        {
            if (x1 == x2)
            {
                return Math.Abs((int) (y1 - y2));
            }
            if (y1 == y2)
            {
                return Math.Abs((int) (x1 - x2));
            }
            return (int) Math.Sqrt((double) (((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))));
        }

        public static double DistanceToLine(double x1, double y1, double x2, double y2, double x, double y, bool ShortLine)
        {
            if ((x1 == x2) && (y1 == y2))
            {
                return -1.0;
            }
            double a = Math.Sqrt(((x - x1) * (x - x1)) + ((y - y1) * (y - y1)));
            double b = Math.Sqrt(((x - x2) * (x - x2)) + ((y - y2) * (y - y2)));
            double xd = x1 + (((x2 - x1) * a) / (a + b));
            double yd = y1 + (((y2 - y1) * a) / (a + b));
            if (ShortLine)
            {
                if (x1 != x2)
                {
                    if (((xd - x1) * (xd - x2)) >= 0.0)
                    {
                        return -1.0;
                    }
                }
                else if (((yd - y1) * (yd - y2)) >= 0.0)
                {
                    return -1.0;
                }
            }
            return Math.Sqrt(((x - xd) * (x - xd)) + ((y - yd) * (y - yd)));
        }

        public static int FixToRange(int vValue, int min, int max)
        {
            if (vValue < min)
            {
                return min;
            }
            if (vValue > max)
            {
                return max;
            }
            return vValue;
        }

        public static int FixValue(int iValue, int iMax, int iMin)
        {
            if (iValue > iMax)
            {
                iValue = iMax;
            }
            if (iValue < iMin)
            {
                iValue = iMin;
            }
            return iValue;
        }

        public static bool GetIntAttribute(int intAttributes, int intValue)
        {
            return ((intAttributes & intValue) == intValue);
        }

        public static double[] GetLineEquationParameter(double x1, double y1, double x2, double y2)
        {
            if (double.IsNaN(x1))
            {
                throw new ArgumentException("x1 is Nan");
            }
            if (double.IsNaN(y1))
            {
                throw new ArgumentException("y1 is Nan");
            }
            if (double.IsNaN(x2))
            {
                throw new ArgumentException("x2 is Nan");
            }
            if (double.IsNaN(y2))
            {
                throw new ArgumentException("y2 is Nan");
            }
            if (x1 != x2)
            {
                double a = (y2 - y1) / (x2 - x1);
                double b = y1 - (a * x1);
                return new double[] { a, b };
            }
            return null;
        }

        public static int GetNearestPoint(Point o, Point[] ps, int Direction)
        {
            int MinDis = 0x7fffffff;
            int MinPDis = 0x7fffffff;
            int MinIndex = -1;
            for (int iCount = 0; iCount < ps.Length; iCount++)
            {
                Point p = ps[iCount];
                if ((p.X != o.X) || (p.Y != o.Y))
                {
                    double angle = Angle((double) o.X, (double) o.Y, (double) p.X, (double) p.Y);
                    bool bolFlag = false;
                    int dis = 0;
                    int pdis = 0;
                    pdis = ((p.X - o.X) * (p.X - o.X)) + ((p.Y - o.Y) * (p.Y - o.Y));
                    switch (Direction)
                    {
                        case 0:
                            bolFlag = (angle <= 45.0) || (angle >= 315.0);
                            dis = p.X - o.X;
                            break;

                        case 1:
                            bolFlag = (angle >= 45.0) && (angle <= 135.0);
                            dis = p.Y - o.Y;
                            break;

                        case 2:
                            bolFlag = (angle >= 135.0) && (angle <= 225.0);
                            dis = p.X - o.X;
                            break;

                        case 3:
                            bolFlag = (angle >= 225.0) && (angle <= 315.0);
                            dis = p.Y - o.Y;
                            break;
                    }
                    if (bolFlag)
                    {
                        dis = Math.Abs(dis);
                        if ((dis <= MinDis) && ((dis < MinDis) || (pdis < MinPDis)))
                        {
                            MinDis = dis;
                            MinPDis = pdis;
                            MinIndex = iCount;
                        }
                    }
                }
            }
            if (MinIndex == -1)
            {
                for (int iCount = 0; iCount < ps.Length; iCount++)
                {
                    Point p = ps[iCount];
                    if ((p.X != o.X) || (p.Y != o.Y))
                    {
                        int dis = -1;
                        switch (Direction)
                        {
                            case 0:
                                if (p.X > o.X)
                                {
                                    dis = p.X - o.X;
                                }
                                break;

                            case 1:
                                if (p.Y > o.Y)
                                {
                                    dis = p.Y - o.Y;
                                }
                                break;

                            case 2:
                                if (p.X < o.X)
                                {
                                    dis = o.X - p.X;
                                }
                                break;

                            case 3:
                                if (p.Y < o.Y)
                                {
                                    dis = o.Y - p.Y;
                                }
                                break;
                        }
                        if ((dis > 0) && (dis < MinDis))
                        {
                            MinDis = dis;
                            MinIndex = iCount;
                        }
                    }
                }
            }
            return MinIndex;
        }

        public static Point[] GetPiePoints(RectangleF bounds, double StartAngle, double EndAngle, int PointCount)
        {
            if (PointCount < 3)
            {
                return null;
            }
            Point[] ps = new Point[PointCount];
            EllipseObject obj = new EllipseObject(bounds);
            double dblStep = (EndAngle - StartAngle) / ((double) (PointCount - 1));
            for (int iCount = 0; iCount < PointCount; iCount++)
            {
                double angle = StartAngle + (dblStep * iCount);
                PointF p = obj.PeripheraPoint2(angle);
                ps[iCount].X = (int) p.X;
                ps[iCount].Y = (int) p.Y;
            }
            return ps;
        }

        public static Color Int32ToColor(int intColor)
        {
            return Color.FromArgb((intColor & 0xff0000) >> 0x10, (intColor & 0xff00) >> 8, intColor & 0xff);
        }

        public static int[] IntersectRange(int a1, int b1, int a2, int b2)
        {
            int temp = 0;
            if (a1 > b1)
            {
                temp = a1;
                a1 = b1;
                b1 = temp;
            }
            if (a2 > b2)
            {
                temp = a2;
                a2 = b2;
                b2 = temp;
            }
            int maxa = Math.Max(a1, a2);
            int minb = Math.Min(b1, b2);
            if (maxa >= minb)
            {
                return new int[] { maxa, minb };
            }
            return null;
        }

        public static bool IntersectWithRange(int a1, int b1, int a2, int b2)
        {
            int temp = 0;
            if (a1 > b1)
            {
                temp = a1;
                a1 = b1;
                b1 = temp;
            }
            if (a2 > b2)
            {
                temp = a2;
                a2 = b2;
                b2 = temp;
            }
            int maxa = Math.Max(a1, a2);
            int minb = Math.Min(b1, b2);
            return (maxa >= minb);
        }

        public static Point LineIntersectPoint(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, bool Beeline)
        {
            double x = 0.0;
            double y = 0.0;
            double a1 = 0.0;
            double a2 = 0.0;
            double b1 = 0.0;
            double b2 = 0.0;
            if (x1 != x2)
            {
                a1 = ((double) (y2 - y1)) / ((double) (x2 - x1));
                b1 = y1 - (a1 * x1);
            }
            if (x3 != x4)
            {
                a2 = ((double) (y4 - y3)) / ((double) (x4 - x3));
                b2 = y3 - (a2 * x3);
            }
            if (x1 == x2)
            {
                if (x3 == x4)
                {
                    if (x1 != x3)
                    {
                        return new Point(-2147483648, -2147483648);
                    }
                    if (Beeline)
                    {
                        if (RangeIntersect(y1, y2, y3, y4))
                        {
                            return new Point(0x7fffffff, 0x7fffffff);
                        }
                        return new Point(-2147483648, -2147483648);
                    }
                    return new Point(0x7fffffff, 0x7fffffff);
                }
                x = x1;
                y = (a2 * x) + b2;
            }
            else if (x3 == x4)
            {
                x = x3;
                y = (a1 * x) + b1;
            }
            else
            {
                if (a1 == a2)
                {
                    if (b1 != b2)
                    {
                        return new Point(-2147483648, -2147483648);
                    }
                    if (Beeline)
                    {
                        if (RangeIntersect(x1, x2, x3, x4))
                        {
                            return new Point(0x7fffffff, 0x7fffffff);
                        }
                        return new Point(-2147483648, -2147483648);
                    }
                    return new Point(0x7fffffff, 0x7fffffff);
                }
                x = (b2 - b1) / (a1 - a2);
                y = (a1 * x) + b1;
            }
            if (Beeline)
            {
                if ((RangeContains((double) x1, (double) x2, x) && RangeContains((double) x3, (double) x4, x)) && (RangeContains((double) y1, (double) y2, y) && RangeContains((double) y3, (double) y4, y)))
                {
                    return new Point((int) x, (int) y);
                }
                return new Point(-2147483648, -2147483648);
            }
            return new Point((int) x, (int) y);
        }

        public static bool LineIntersectsWith(Rectangle rect, int x1, int y1, int x2, int y2)
        {
            return (rect.Contains(x1, y1) || (rect.Contains(x2, y2) || (LineIntersectsWith(x1, y1, x2, y2, rect.Left, rect.Top, rect.Right, rect.Top) || (LineIntersectsWith(x1, y1, x2, y2, rect.Right, rect.Top, rect.Right, rect.Bottom) || (LineIntersectsWith(x1, y1, x2, y2, rect.Right, rect.Bottom, rect.Left, rect.Bottom) || LineIntersectsWith(x1, y1, x2, y2, rect.Left, rect.Bottom, rect.Left, rect.Top))))));
        }

        public static bool LineIntersectsWith(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
        {
            Point p = LineIntersectPoint(x1, y1, x2, y2, x3, y3, x4, y4, true);
            if ((p.X == -2147483648) && (p.Y == -2147483648))
            {
                return false;
            }
            return true;
        }

        public static bool RangeContains(double x1, double x2, double x)
        {
            if (x1 < x2)
            {
                return ((x >= x1) && (x <= x2));
            }
            return ((x >= x2) && (x <= x1));
        }

        public static bool RangeContains(int x1, int x2, int x)
        {
            if (x1 < x2)
            {
                return ((x >= x1) && (x <= x2));
            }
            return ((x >= x2) && (x <= x1));
        }

        public static bool RangeIntersect(int a1, int b1, int a2, int b2)
        {
            return ((a1 <= b2) && (a2 <= b1));
        }

        public static void RectangleClipLines(Rectangle ClipRectangle, Point[] LinesPoints)
        {
            if (ClipRectangle.IsEmpty)
            {
                throw new ArgumentException("ClipRectangle is Empty", "ClipRectangle");
            }
            if (LinesPoints == null)
            {
                throw new ArgumentNullException("LinesPoints");
            }
            if (LinesPoints.Length == 0)
            {
                throw new ArgumentException("LinesPoints is empty", "LinesPoints");
            }
            if ((LinesPoints.Length % 2) != 0)
            {
                throw new ArgumentException("LinesPoints is error", "LinesPoints");
            }
            Point BlankPoint = new Point(-2147483648, -2147483648);
            int left = ClipRectangle.Left;
            int top = ClipRectangle.Top;
            int right = ClipRectangle.Right;
            int bottom = ClipRectangle.Bottom;
            for (int iCount = 0; iCount < LinesPoints.Length; iCount += 2)
            {
                Point p1 = LinesPoints[iCount];
                Point p2 = LinesPoints[iCount + 1];
                bool c1 = ClipRectangle.Contains(p1);
                if (p1.Equals(p2))
                {
                    if (!c1)
                    {
                        LinesPoints[iCount] = BlankPoint;
                        LinesPoints[iCount + 1] = BlankPoint;
                    }
                }
                else
                {
                    bool c2 = ClipRectangle.Contains(p2);
                    if (!c1 || !c2)
                    {
                        if (p1.X == p2.X)
                        {
                            if ((p1.X >= left) && (p1.X <= right))
                            {
                                LinesPoints[iCount].Y = FixToRange(p1.Y, top, bottom);
                                LinesPoints[iCount + 1].Y = FixToRange(p2.Y, top, bottom);
                            }
                            else
                            {
                                LinesPoints[iCount] = BlankPoint;
                                LinesPoints[iCount + 1] = BlankPoint;
                            }
                        }
                        else if (p1.Y == p2.Y)
                        {
                            if ((p1.Y >= top) && (p1.Y <= bottom))
                            {
                                LinesPoints[iCount].X = FixToRange(p1.X, left, right);
                                LinesPoints[iCount + 1].X = FixToRange(p2.X, left, right);
                            }
                            else
                            {
                                LinesPoints[iCount] = BlankPoint;
                                LinesPoints[iCount + 1] = BlankPoint;
                            }
                        }
                        else
                        {
                            double[] ps = GetLineEquationParameter((double) p1.X, (double) p1.Y, (double) p2.X, (double) p2.Y);
                            double a = ps[0];
                            double b = ps[1];
                            if (p1.X < left)
                            {
                                p1.X = left;
                                p1.Y = (int) ((a * p1.X) + b);
                            }
                            else if (p1.X > right)
                            {
                                p1.X = right;
                                p1.Y = (int) ((a * p1.X) + b);
                            }
                            if (p1.Y < top)
                            {
                                p1.Y = top;
                                p1.X = (int) ((p1.Y - b) / a);
                            }
                            else if (p1.Y > bottom)
                            {
                                p1.Y = bottom;
                                p1.X = (int) ((p1.Y - b) / a);
                            }
                            if (p2.X < left)
                            {
                                p2.X = left;
                                p2.Y = (int) ((a * p2.X) + b);
                            }
                            else if (p2.X > right)
                            {
                                p2.X = right;
                                p2.Y = (int) ((a * p2.X) + b);
                            }
                            if (p2.Y < top)
                            {
                                p2.Y = top;
                                p2.X = (int) ((p2.Y - b) / a);
                            }
                            else if (p2.Y > bottom)
                            {
                                p2.Y = bottom;
                                p2.X = (int) ((p2.Y - b) / a);
                            }
                            bool flag = false;
                            if ((((p1.X >= left) && (p1.X <= right)) && ((p1.Y >= top) && (p1.Y <= bottom))) && (((p2.X >= left) && (p2.X <= right)) && ((p2.Y >= top) && (p2.Y <= bottom))))
                            {
                                flag = true;
                            }
                            if (flag)
                            {
                                LinesPoints[iCount] = p1;
                                LinesPoints[iCount + 1] = p2;
                            }
                            else
                            {
                                LinesPoints[iCount] = BlankPoint;
                                LinesPoints[iCount + 1] = BlankPoint;
                            }
                        }
                    }
                }
            }
        }

        public static Point RotatePoint(Point o, Point p, double angle)
        {
            if ((o.X == p.X) && (o.Y == p.Y))
            {
                return p;
            }
            double l = ((p.X - o.X) * (p.X - o.X)) + ((p.Y - o.Y) * (p.Y - o.Y));
            l = Math.Sqrt(l);
            double alf = Math.Atan2((double) (p.Y - o.Y), (double) (p.X - o.X)) - angle;
            Point p2 = Point.Empty;
            p2.X = o.X + ((int) (l * Math.Cos(alf)));
            p2.Y = o.Y + ((int) (l * Math.Sin(alf)));
            return p2;
        }

        public static PointF RotatePoint(PointF o, PointF p, double angle)
        {
            if ((o.X == p.X) && (o.Y == p.Y))
            {
                return p;
            }
            double l = ((p.X - o.X) * (p.X - o.X)) + ((p.Y - o.Y) * (p.Y - o.Y));
            l = Math.Sqrt(l);
            double alf = Math.Atan2((double) (p.Y - o.Y), (double) (p.X - o.X)) - angle;
            PointF p2 = PointF.Empty;
            p2.X = o.X + ((float) (l * Math.Cos(alf)));
            p2.Y = o.Y + ((float) (l * Math.Sin(alf)));
            return p2;
        }

        public static int SearchInt32Array(int[] intValues, int intMatch, bool SplitSearch)
        {
            if (intValues != null)
            {
                int StartIndex = 0;
                int EndIndex = intValues.Length - 1;
                if ((intValues.Length < 10) || !SplitSearch)
                {
                    for (int iCount = StartIndex; iCount <= EndIndex; iCount++)
                    {
                        if (intMatch == intValues[iCount])
                        {
                            return iCount;
                        }
                    }
                }
                else
                {
                    int MiddleIndex = 0;
                    for (int Length = EndIndex - StartIndex; Length > 10; Length = EndIndex - StartIndex)
                    {
                        MiddleIndex = StartIndex + (Length / 2);
                        if (intValues[MiddleIndex] == intMatch)
                        {
                            return MiddleIndex;
                        }
                        if (intValues[MiddleIndex] > intMatch)
                        {
                            EndIndex = MiddleIndex;
                        }
                        else
                        {
                            StartIndex = MiddleIndex;
                        }
                    }
                    for (int iCount = StartIndex; iCount <= EndIndex; iCount++)
                    {
                        if (intMatch == intValues[iCount])
                        {
                            return iCount;
                        }
                    }
                }
            }
            return -1;
        }

        public static int SetIntAttribute(int intAttributes, int intValue, bool bolSet)
        {
            return (bolSet ? (intAttributes | intValue) : (intAttributes & ~intValue));
        }
    }
}

